#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
代码整理工具
功能：根据指定目录和文件扩展名整理源代码，显示在MEMO中并统计行数
"""

import os
import tkinter as tk
from tkinter import ttk, filedialog, messagebox, scrolledtext
import threading
from tkinter.scrolledtext import ScrolledText
from typing import List, Tuple, Dict
import re

# 尝试导入tkinter的拖放支持
try:
    from tkinterdnd2 import DND_FILES, TkinterDnD
    TKINTER_DND_AVAILABLE = True
except ImportError:
    TKINTER_DND_AVAILABLE = False


class CodeOrganizer:
    def __init__(self):
        # 根据是否支持拖放选择使用不同的根窗口
        if TKINTER_DND_AVAILABLE:
            self.root = TkinterDnD.Tk()
        else:
            self.root = tk.Tk()
        
        self.root.title("代码整理工具")
        self.root.geometry("700x800")  # 增加高度以适应新的配置区域
        
        # 设置应用程序图标
        self.set_window_icon()
        
        # 变量
        self.extensions_var = tk.StringVar(value=".py,.js,.html,.css,.java,.cpp,.c,.h")
        self.recursive_var = tk.BooleanVar(value=True)
        self.total_lines = 0
        self.total_files = 0
        
        # 行数限制配置（用户可自定义）
        self.max_display_lines_var = tk.StringVar(value="100000")  # 默认10万行
        self.warning_lines_var = tk.StringVar(value="50000")      # 默认5万行警告
        self.enable_line_limit = tk.BooleanVar(value=False)        # 是否启用行数限制
        
        self.setup_ui()
        
        # 设置拖放功能（如果可用）
        self.setup_drag_drop()
    
    def setup_ui(self):
        """设置用户界面"""
        # 主框架
        main_frame = ttk.Frame(self.root, padding="10")
        main_frame.grid(row=0, column=0, sticky="nsew")
        
        # 配置网格权重
        self.root.columnconfigure(0, weight=1)
        self.root.rowconfigure(0, weight=1)
        main_frame.columnconfigure(1, weight=1)
        main_frame.rowconfigure(5, weight=1)
        
        # 路径选择（支持目录和文件）
        ttk.Label(main_frame, text="路径选择:").grid(row=0, column=0, sticky="nw", pady=5)
        path_frame = ttk.Frame(main_frame)
        path_frame.grid(row=0, column=1, columnspan=2, sticky="ew", pady=5)
        path_frame.columnconfigure(0, weight=1)
        path_frame.rowconfigure(0, weight=1)
        
        # 多行文本框用于输入多个路径（目录或文件）
        self.directory_text = tk.Text(path_frame, height=4, width=50, wrap=tk.WORD)
        self.directory_text.grid(row=0, column=0, sticky="ew", padx=(0, 5))
        
        # 按钮框架
        button_frame = ttk.Frame(path_frame)
        button_frame.grid(row=0, column=1, sticky="n")
        ttk.Button(button_frame, text="添加目录", command=self.browse_directory).pack(pady=(0, 5))
        ttk.Button(button_frame, text="添加文件", command=self.browse_files).pack(pady=(0, 5))
        ttk.Button(button_frame, text="清空", command=self.clear_directories).pack()
        
        # 添加说明标签
        ttk.Label(path_frame, text="(每行一个路径，支持目录和具体文件)").grid(row=1, column=0, sticky="w", pady=(5, 0))
        
        # 文件扩展名
        ttk.Label(main_frame, text="文件扩展名:").grid(row=1, column=0, sticky=tk.W, pady=5)
        ext_frame = ttk.Frame(main_frame)
        ext_frame.grid(row=1, column=1, columnspan=2, sticky="ew", pady=5)
        ext_frame.columnconfigure(0, weight=1)
        
        ttk.Entry(ext_frame, textvariable=self.extensions_var, width=50).grid(row=0, column=0, sticky="ew")
        ttk.Label(ext_frame, text="(用逗号分隔，如: .py,.js,.html)").grid(row=1, column=0, sticky=tk.W)
        
        # 递归搜索选项
        ttk.Checkbutton(main_frame, text="搜索子目录", variable=self.recursive_var).grid(row=2, column=1, sticky=tk.W, pady=5)
        
        # 行数限制配置区域
        limit_frame = ttk.LabelFrame(main_frame, text="显示限制设置", padding="5")
        limit_frame.grid(row=3, column=0, columnspan=3, sticky="ew", pady=5)
        limit_frame.columnconfigure(1, weight=1)
        limit_frame.columnconfigure(3, weight=1)
        
        # 启用限制选项
        ttk.Checkbutton(
            limit_frame, 
            text="启用行数限制（仅影响显示，不影响统计）", 
            variable=self.enable_line_limit
        ).grid(row=0, column=0, columnspan=4, sticky="w", pady=(0, 5))
        
        # 最大显示行数
        ttk.Label(limit_frame, text="最大显示行数:").grid(row=1, column=0, sticky="w", padx=(20, 5))
        max_lines_entry = ttk.Entry(limit_frame, textvariable=self.max_display_lines_var, width=10)
        max_lines_entry.grid(row=1, column=1, sticky="w", padx=5)
        
        # 警告阈值
        ttk.Label(limit_frame, text="性能警告阈值:").grid(row=1, column=2, sticky="w", padx=(20, 5))
        warning_lines_entry = ttk.Entry(limit_frame, textvariable=self.warning_lines_var, width=10)
        warning_lines_entry.grid(row=1, column=3, sticky="w", padx=5)
        
        # 说明文本
        ttk.Label(
            limit_frame, 
            text="说明：行数限制只影响界面显示，不会影响实际的代码行数统计和保存结果", 
            font=("Consolas", 8),
            foreground="gray"
        ).grid(row=2, column=0, columnspan=4, sticky="w", pady=(5, 0), padx=(20, 0))
        
        # 按钮
        button_frame = ttk.Frame(main_frame)
        button_frame.grid(row=4, column=0, columnspan=3, pady=10)
        
        ttk.Button(button_frame, text="开始整理", command=self.start_organize).pack(side=tk.LEFT, padx=5)
        ttk.Button(button_frame, text="清空结果", command=self.clear_results).pack(side=tk.LEFT, padx=5)
        ttk.Button(button_frame, text="清除空白行", command=self.remove_blank_lines).pack(side=tk.LEFT, padx=5)
        ttk.Button(button_frame, text="保存结果", command=self.save_results).pack(side=tk.LEFT, padx=5)
        
        # 结果显示区域
        result_frame = ttk.LabelFrame(main_frame, text="代码内容", padding="5")
        result_frame.grid(row=5, column=0, columnspan=3, sticky="nsew", pady=10)
        result_frame.columnconfigure(0, weight=1)
        result_frame.rowconfigure(0, weight=1)
        
        # 文本框
        self.text_area: ScrolledText = scrolledtext.ScrolledText(
            result_frame, 
            wrap=tk.NONE, 
            font=("Consolas", 10),
            height=25
        )
        self.text_area.grid(row=0, column=0, sticky="nsew")
        
        # 状态栏
        self.status_frame = ttk.Frame(main_frame)
        self.status_frame.grid(row=6, column=0, columnspan=3, sticky="ew", pady=5)
        
        self.status_label = ttk.Label(self.status_frame, text="就绪")
        self.status_label.pack(side=tk.LEFT)
        
        self.progress = ttk.Progressbar(self.status_frame, mode='indeterminate')
        self.progress.pack(side=tk.RIGHT, padx=(10, 0))
    
    def browse_directory(self):
        """浏览选择目录并添加到列表中"""
        directory = filedialog.askdirectory(title="选择源代码目录")
        if directory:
            # 获取当前内容
            current_content = self.directory_text.get(1.0, tk.END).strip()
            # 如果不为空，添加换行
            if current_content:
                self.directory_text.insert(tk.END, "\n")
            # 添加新目录
            self.directory_text.insert(tk.END, directory)
    
    def browse_files(self):
        """浏览选择文件并添加到列表中"""
        files = filedialog.askopenfilenames(
            title="选择源代码文件",
            filetypes=[
                ("Python文件", "*.py"),
                ("JavaScript文件", "*.js"),
                ("HTML文件", "*.html"),
                ("CSS文件", "*.css"),
                ("Java文件", "*.java"),
                ("C++文件", "*.cpp;*.cc;*.cxx"),
                ("C文件", "*.c;*.h"),
                ("所有支持的文件", "*.py;*.js;*.html;*.css;*.java;*.cpp;*.cc;*.cxx;*.c;*.h"),
                ("所有文件", "*.*")
            ]
        )
        
        if files:
            # 获取当前内容
            current_content = self.directory_text.get(1.0, tk.END).strip()
            # 如果不为空，添加换行
            if current_content:
                self.directory_text.insert(tk.END, "\n")
            
            # 添加所有选中的文件
            for file_path in files:
                if current_content or self.directory_text.get(1.0, tk.END).strip():
                    self.directory_text.insert(tk.END, "\n")
                self.directory_text.insert(tk.END, file_path)
    
    def clear_directories(self):
        """清空目录列表"""
        self.directory_text.delete(1.0, tk.END)
    
    def setup_drag_drop(self):
        """设置拖放功能"""
        if not TKINTER_DND_AVAILABLE:
            return
        
        try:
            # 为目录文本框设置拖放功能
            self.directory_text.drop_target_register(DND_FILES)
            self.directory_text.dnd_bind('<<Drop>>', self.on_drop)
            
            # 添加拖放提示标签
            self.drop_hint_label = ttk.Label(
                self.directory_text.master, 
                text="📁 拖拽文件或文件夹到这里", 
                foreground='gray',
                font=('Arial', 8)
            )
            self.drop_hint_label.place(relx=0.5, rely=0.5, anchor='center')
            
            # 当文本框有内容时隐藏提示
            self.directory_text.bind('<KeyRelease>', self.update_drop_hint)
            self.directory_text.bind('<Button-1>', self.update_drop_hint)
            
        except Exception as e:
            print(f"设置拖放功能时出错: {e}")
    
    def update_drop_hint(self, event=None):
        """更新拖放提示的显示状态"""
        if not TKINTER_DND_AVAILABLE:
            return
            
        try:
            content = self.directory_text.get(1.0, tk.END).strip()
            if content:
                self.drop_hint_label.place_forget()
            else:
                self.drop_hint_label.place(relx=0.5, rely=0.5, anchor='center')
        except:
            pass
    
    def on_drop(self, event):
        """处理拖放事件"""
        if not TKINTER_DND_AVAILABLE:
            return
            
        try:
            # 获取拖放的文件路径
            dropped_files = self.root.tk.splitlist(event.data)
            
            # 过滤出有效的目录和文件
            valid_paths = []
            for file_path in dropped_files:
                file_path = file_path.replace('\\', '/').strip('"')
                if os.path.exists(file_path):
                    # 文件和目录都直接添加，不再转换
                    if file_path not in valid_paths:
                        valid_paths.append(file_path)
            
            if valid_paths:
                # 获取当前内容并去重
                current_content = self.directory_text.get(1.0, tk.END).strip()
                existing_paths = set()
                if current_content:
                    existing_paths = set(line.strip() for line in current_content.split('\n') if line.strip())
                
                # 添加新路径（去重）
                new_paths = []
                for path in valid_paths:
                    if path not in existing_paths:
                        new_paths.append(path)
                        existing_paths.add(path)
                
                # 更新文本框
                new_content = '\n'.join(existing_paths) if existing_paths else ''
                self.directory_text.delete(1.0, tk.END)
                if new_content:
                    self.directory_text.insert(1.0, new_content)
                
                # 更新提示
                self.update_drop_hint()
                
                # 显示提示信息
                if new_paths:
                    self.status_label.config(text=f"已添加 {len(new_paths)} 个新路径")
                else:
                    self.status_label.config(text="所有路径已存在")
                self.root.after(2000, lambda: self.status_label.config(text="就绪"))
            
        except Exception as e:
            messagebox.showerror("拖放错误", f"处理拖放文件时出错: {e}")
    
    def get_directories(self) -> List[str]:
        """获取目录列表"""
        content = self.directory_text.get(1.0, tk.END).strip()
        if not content:
            return []
        
        directories = []
        for line in content.split('\n'):
            path = line.strip()
            if path and os.path.isdir(path):
                directories.append(path)
        return directories
    
    def get_files(self) -> List[str]:
        """获取文件列表"""
        content = self.directory_text.get(1.0, tk.END).strip()
        if not content:
            return []
        
        files = []
        for line in content.split('\n'):
            path = line.strip()
            if path and os.path.isfile(path):
                files.append(path)
        return files
    
    def get_extensions(self) -> List[str]:
        """获取文件扩展名列表"""
        extensions_str = self.extensions_var.get().strip()
        if not extensions_str:
            return []
        
        extensions = [ext.strip() for ext in extensions_str.split(',')]
        return [ext if ext.startswith('.') else f'.{ext}' for ext in extensions if ext]
    
    def get_max_display_lines(self) -> int:
        """获取用户设置的最大显示行数"""
        try:
            return max(1000, int(self.max_display_lines_var.get()))  # 最小1000行
        except ValueError:
            return 100000  # 默认值
    
    def get_warning_lines(self) -> int:
        """获取用户设置的警告阈值行数"""
        try:
            max_lines = self.get_max_display_lines()
            warning_lines = int(self.warning_lines_var.get())
            return min(max_lines - 1000, max(1000, warning_lines))  # 警告阈值不能超过最大值
        except ValueError:
            return 50000  # 默认值
    
    def find_source_files(self, directories: List[str], extensions: List[str], recursive: bool) -> List[str]:
        """查找源代码文件"""
        source_files = []
        
        try:
            # 处理目录
            for directory in directories:
                if not os.path.isdir(directory):
                    print(f"警告：目录 '{directory}' 不存在，跳过")
                    continue
                    
                if recursive:
                    for root, dirs, files in os.walk(directory):
                        for file in files:
                            if any(file.lower().endswith(ext.lower()) for ext in extensions):
                                file_path = os.path.join(root, file)
                                # 使用绝对路径并标准化
                                abs_path = os.path.abspath(file_path)
                                if abs_path not in source_files:
                                    source_files.append(abs_path)
                else:
                    for file in os.listdir(directory):
                        file_path = os.path.join(directory, file)
                        if os.path.isfile(file_path) and any(file.lower().endswith(ext.lower()) for ext in extensions):
                            # 使用绝对路径并标准化
                            abs_path = os.path.abspath(file_path)
                            if abs_path not in source_files:
                                source_files.append(abs_path)
        
        except Exception as e:
            messagebox.showerror("错误", f"搜索文件时出错: {str(e)}")
            return []
        
        return sorted(source_files)
    
    def filter_files(self, files: List[str], extensions: List[str]) -> List[str]:
        """过滤文件列表，只保留指定扩展名的文件"""
        filtered_files = []
        seen_files = set()  # 用于去重
        
        for file_path in files:
            if not os.path.isfile(file_path):
                continue
                
            # 使用绝对路径并标准化
            abs_path = os.path.abspath(file_path)
            if abs_path in seen_files:
                continue
                
            # 检查文件扩展名
            file_ext = os.path.splitext(file_path)[1].lower()
            if any(ext.lower() == file_ext for ext in extensions):
                filtered_files.append(abs_path)
                seen_files.add(abs_path)
        
        return sorted(filtered_files)
    
    def check_duplicate_files(self, files: List[str], directories: List[str], extensions: List[str], recursive: bool) -> List[str]:
        """检查文件是否已存在于目录中，避免重复整理"""
        if not directories or not files:
            return files
            
        try:
            # 获取目录中的所有文件
            directory_files = self.find_source_files(directories, extensions, recursive)
            directory_files_set = set(directory_files)
            
            # 过滤掉已存在于目录中的文件
            unique_files = []
            for file_path in files:
                abs_file_path = os.path.abspath(file_path)
                # 检查文件是否已存在于目录扫描结果中
                if abs_file_path in directory_files_set:
                    print(f"跳过重复文件: {file_path}")
                else:
                    unique_files.append(file_path)
            
            return unique_files
        except Exception as e:
            print(f"检查重复文件时出错: {e}")
            return files  # 出错时返回原始文件列表
    
    def read_file_content(self, file_path: str) -> Tuple[str, int]:
        """读取文件内容并返回内容和行数"""
        try:
            # 尝试不同的编码
            encodings = ['utf-8', 'gbk', 'gb2312', 'latin-1']
            content = ""
            
            for encoding in encodings:
                try:
                    with open(file_path, 'r', encoding=encoding) as f:
                        content = f.read()
                    break
                except UnicodeDecodeError:
                    continue
            
            if not content:
                # 如果所有编码都失败，使用二进制模式并忽略错误
                with open(file_path, 'r', encoding='utf-8', errors='ignore') as f:
                    content = f.read()
            
            lines = len(content.splitlines())
            return content, lines
            
        except Exception as e:
            error_msg = f"无法读取文件: {str(e)}"
            return error_msg, 0
    
    def organize_code(self):
        """整理代码的主要逻辑"""
        directories = self.get_directories()
        files = self.get_files()
        
        if not directories and not files:
            messagebox.showerror("错误", "请输入有效的目录路径或文件路径")
            return
        
        extensions = self.get_extensions()
        if not extensions:
            messagebox.showerror("错误", "请输入文件扩展名")
            return
        
        recursive = self.recursive_var.get()
        
        # 更新状态
        self.status_label.config(text="正在处理文件...")
        self.progress.start()
        
        # 查找目录中的文件
        source_files = self.find_source_files(directories, extensions, recursive)
        
        # 处理单独添加的文件
        if files:
            # 过滤文件扩展名
            filtered_files = self.filter_files(files, extensions)
            
            # 检查重复文件（避免与目录中的文件重复）
            if source_files:  # 如果有目录中的文件，检查重复
                unique_files = self.check_duplicate_files(filtered_files, directories, extensions, recursive)
            else:
                unique_files = filtered_files
            
            # 合并文件列表（在合并前再次检查是否与现有文件重复）
            existing_files_set = set(source_files)
            for file_path in unique_files:
                abs_file_path = os.path.abspath(file_path)
                if abs_file_path not in existing_files_set:
                    source_files.append(abs_file_path)
                    existing_files_set.add(abs_file_path)
                else:
                    print(f"跳过重复文件: {file_path}")
            
            source_files = sorted(source_files)
        
        if not source_files:
            self.progress.stop()
            self.status_label.config(text="未找到匹配的源代码文件")
            messagebox.showinfo("信息", "未找到匹配的源代码文件")
            return
        
        # 清空文本区域
        self.text_area.delete(1.0, tk.END)
        
        # 添加头部信息
        header = f"""
{'='*80}
代码整理报告
{'='*80}
目录: {', '.join(directories)}
扩展名: {', '.join(extensions)}
递归搜索: {'是' if recursive else '否'}
找到文件数: {len(source_files)}
{'='*80}

"""
        #self.text_area.insert(tk.END, header)
        
        # 处理每个文件
        self.total_lines = 0
        self.total_files = len(source_files)
        current_content_lines = 0  # 当前已显示的行数
        display_stopped = False    # 是否已停止显示
        
        # 获取用户配置的行数限制
        max_display_lines = self.get_max_display_lines()
        warning_lines = self.get_warning_lines()
        
        for i, file_path in enumerate(source_files):
            self.status_label.config(text=f"正在处理文件 {i+1}/{len(source_files)}: {os.path.basename(file_path)}")
            self.root.update()
            
            # 读取文件内容
            content, lines = self.read_file_content(file_path)
            
            # 重要：统计总行数不受显示限制影响
            self.total_lines += lines
            
            # 只有在未停止显示时才处理显示逻辑
            if not display_stopped:
                # 检查行数限制（仅影响显示）
                if self.enable_line_limit.get():
                    # 如果当前内容加上新文件内容超过限制
                    if current_content_lines + lines > max_display_lines:
                        # 计算可以显示的行数
                        remaining_lines = max_display_lines - current_content_lines
                        
                        if remaining_lines > 0:
                            # 只显示部分内容
                            content_lines = content.splitlines()
                            truncated_content = '\n'.join(content_lines[:remaining_lines])
                            
                            # 添加内容
                            if current_content_lines > 0:  # 如果已有内容，先添加换行
                                self.text_area.insert(tk.END, "\n")
                            self.text_area.insert(tk.END, truncated_content)
                            current_content_lines += remaining_lines
                        
                        # 添加截断提示
                        truncate_msg = f"\n\n{'='*60}\n内容被截断：超过最大显示行数限制 ({max_display_lines:,} 行)\n"
                        truncate_msg += f"剩余 {len(source_files) - i - 1} 个文件未显示，但统计将继续...\n"
                        truncate_msg += f"注意：统计信息包含所有文件，不受显示限制影响\n{'='*60}\n"
                        self.text_area.insert(tk.END, truncate_msg)
                        
                        # 标记停止显示，但继续统计
                        display_stopped = True
                        
                        # 提醒用户（只在第一次截断时显示）
                        if not hasattr(self, '_truncate_notified'):
                            self._truncate_notified = True
                            message = (
                                f"由于超过用户设置的显示限制，内容已被截断在 {max_display_lines:,} 行\n\n"
                                f"📊 统计将继续进行，最终结果包含所有文件：\n"
                                f"- 总文件数：{self.total_files}\n"
                                f"- 已处理文件：{i + 1}\n"
                                f"- 剩余文件：{len(source_files) - i - 1}\n\n"
                                f"💾 使用'保存结果'可获取完整内容"
                            )
                            messagebox.showinfo("显示已截断，统计继续", message)
                    else:
                        # 正常显示
                        if current_content_lines > 0:  # 如果已有内容，先添加换行
                            self.text_area.insert(tk.END, "\n")
                        self.text_area.insert(tk.END, content)
                        current_content_lines += lines
                else:
                    # 不启用行数限制，直接显示
                    if current_content_lines > 0:  # 如果已有内容，先添加换行
                        self.text_area.insert(tk.END, "\n")
                    self.text_area.insert(tk.END, content)
                    current_content_lines += lines
                    
                    # 但仍然给出性能警告
                    if current_content_lines > warning_lines and i == 0:  # 只在第一个文件警告一次
                        message = (
                            f"内容较大（已超过 {warning_lines:,} 行），可能影响界面性能\n\n"
                            f"是否继续显示所有内容？\n\n"
                            f"选择'否'将启用行数限制功能"
                        )
                        response = messagebox.askyesno("性能警告", message)
                        
                        if not response:
                            # 用户选择启用行数限制
                            self.enable_line_limit.set(True)
                            # 重新处理当前文件
                            if current_content_lines > max_display_lines:
                                # 截断已显示的内容
                                all_content = self.text_area.get(1.0, tk.END)
                                content_lines = all_content.splitlines()
                                truncated_content = '\n'.join(content_lines[:max_display_lines])
                                
                                self.text_area.delete(1.0, tk.END)
                                self.text_area.insert(1.0, truncated_content)
                                
                                truncate_msg = f"\n\n{'='*60}\n内容被截断：超过最大显示行数限制 ({max_display_lines:,} 行)\n"
                                truncate_msg += f"剩余 {len(source_files) - i - 1} 个文件未显示，但统计将继续...\n"
                                truncate_msg += f"注意：统计信息包含所有文件，不受显示限制影响\n{'='*60}\n"
                                self.text_area.insert(tk.END, truncate_msg)
                                display_stopped = True
        
        # 添加总结
        summary = f"""
{'='*80}
整理完成
{'='*80}
总文件数: {self.total_files}
总代码行数: {self.total_lines}
{'='*80}
"""
        #self.text_area.insert(tk.END, summary)
        
        # 滚动到顶部
        self.text_area.see(1.0)
        
        # 更新状态
        self.progress.stop()
        self.status_label.config(text=f"完成 - 共处理 {self.total_files} 个文件，{self.total_lines} 行代码")
    
    def start_organize(self):
        """在新线程中开始整理代码"""
        # 使用线程避免界面冻结
        thread = threading.Thread(target=self.organize_code, daemon=True)
        thread.start()
    
    def clear_results(self):
        """清空结果"""
        self.text_area.delete(1.0, tk.END)
        self.total_lines = 0
        self.total_files = 0
        self.status_label.config(text="就绪")
        # 重置截断通知标记
        if hasattr(self, '_truncate_notified'):
            delattr(self, '_truncate_notified')
    
    def save_results(self):
        """保存结果到文件 - 始终保存完整内容，不受显示限制影响"""
        content = self.text_area.get(1.0, tk.END)
        if not content.strip():
            messagebox.showwarning("警告", "没有内容可保存")
            return
        
        # 检查是否内容被截断
        is_truncated = "内容被截断" in content
        
        if is_truncated:
            # 如果内容被截断，提供选项
            response = messagebox.askyesnocancel(
                "保存选项",
                "检测到当前显示内容被截断。\n\n"
                "请选择保存方式：\n\n"
                "'是' - 保存完整内容（重新生成，无行数限制）\n"
                "'否' - 保存当前显示内容（被截断的）\n"
                "'取消' - 不保存"
            )
            
            if response is None:  # 取消
                return
            elif response:  # 是 - 保存完整内容
                self._save_complete_content()
                return
            # 否 - 继续保存当前内容
        
        # 保存当前显示内容
        self._save_current_content(content)
    
    def _save_current_content(self, content):
        """保存当前显示的内容"""
        file_path = filedialog.asksaveasfilename(
            title="保存当前显示的代码内容",
            defaultextension=".txt",
            filetypes=[
                ("文本文件", "*.txt"),
                ("所有文件", "*.*")
            ]
        )
        
        if file_path:
            try:
                with open(file_path, 'w', encoding='utf-8') as f:
                    f.write(content)
                messagebox.showinfo("成功", f"当前显示内容已保存到: {file_path}")
            except Exception as e:
                messagebox.showerror("错误", f"保存文件时出错: {str(e)}")
    
    def _save_complete_content(self):
        """重新生成并保存完整内容（不受行数限制）"""
        # 获取当前配置
        directories = self.get_directories()
        if not directories:
            messagebox.showerror("错误", "请先选择目录并执行整理操作")
            return
        
        extensions = self.get_extensions()
        if not extensions:
            messagebox.showerror("错误", "请先设置文件扩展名")
            return
        
        recursive = self.recursive_var.get()
        
        # 选择保存文件
        file_path = filedialog.asksaveasfilename(
            title="保存完整代码内容（无行数限制）",
            defaultextension=".txt",
            filetypes=[
                ("文本文件", "*.txt"),
                ("所有文件", "*.*")
            ]
        )
        
        if not file_path:
            return
        
        try:
            # 显示进度
            self.status_label.config(text="正在生成完整内容并保存...")
            self.progress.start()
            self.root.update()
            
            # 查找文件
            source_files = self.find_source_files(directories, extensions, recursive)
            
            if not source_files:
                messagebox.showinfo("信息", "未找到匹配的源代码文件")
                return
            
            # 直接写入文件，避免内存问题
            with open(file_path, 'w', encoding='utf-8') as f:
                total_lines = 0
                
                for i, file_path_source in enumerate(source_files):
                    self.status_label.config(text=f"正在处理文件 {i+1}/{len(source_files)}: {os.path.basename(file_path_source)}")
                    self.root.update()
                    
                    # 读取文件内容
                    content, lines = self.read_file_content(file_path_source)
                    total_lines += lines
                    
                    # 写入文件
                    f.write(content)
                    if i < len(source_files) - 1:  # 不是最后一个文件
                        f.write('\n')
            
            self.progress.stop()
            self.status_label.config(text="完整内容保存完成")
            
            messagebox.showinfo(
                "成功", 
                f"完整代码内容已保存到: {file_path}\n\n"
                f"统计信息：\n"
                f"- 文件数：{len(source_files)}\n"
                f"- 总行数：{total_lines:,}"
            )
            
        except Exception as e:
            self.progress.stop()
            self.status_label.config(text="保存失败")
            messagebox.showerror("错误", f"生成完整内容时出错: {str(e)}")
    
    def remove_blank_lines(self):
        """清除空白行功能 - 优化大文件处理"""
        content = self.text_area.get(1.0, tk.END)
        if not content.strip():
            messagebox.showwarning("警告", "没有内容可处理")
            return
        
        try:
            # 显示处理进度
            self.status_label.config(text="正在处理空白行...")
            self.progress.start()
            self.root.update()
            
            # 使用更高效的方式处理大文本
            # 首先获取内容长度以评估处理方式
            content_length = len(content)
            
            if content_length > 1000000:  # 如果内容超过1MB
                # 对于超大文件，使用流式处理
                self._process_large_content(content)
            else:
                # 对于较小文件，使用标准处理
                self._process_normal_content(content)
                
        except Exception as e:
            self.progress.stop()
            self.status_label.config(text="处理失败")
            messagebox.showerror("错误", f"清除空白行时出错: {str(e)}")
    
    def _process_normal_content(self, content):
        """处理普通大小的内容"""
        try:
            # 分割成行
            lines = content.splitlines()
            
            # 过滤掉空白行和只有空格的行
            filtered_lines = []
            for line in lines:
                # 检查是否为空行或只包含空格/制表符
                if line.strip():  # strip()移除前后空白字符，如果结果不为空则保留该行
                    filtered_lines.append(line)
            
            # 统计处理前后的行数
            original_lines = len(lines)
            new_lines = len(filtered_lines)
            removed_lines = original_lines - new_lines
            
            # 重新组合内容
            new_content = '\n'.join(filtered_lines)
            
            # 更新文本区域内容
            self.text_area.delete(1.0, tk.END)
            self.text_area.insert(1.0, new_content)
            
            # 更新总行数
            self.total_lines = new_lines
            
            # 停止进度条
            self.progress.stop()
            
            # 更新状态栏
            self.status_label.config(text=f"清除空白行完成 - 删除了 {removed_lines} 行，剩余 {new_lines} 行代码")
            
            # 显示处理结果
            # messagebox.showinfo(
            #     "处理完成", 
            #     f"清除空白行操作完成！\n\n"
            #     f"原始行数: {original_lines}\n"
            #     f"删除空白行: {removed_lines}\n"
            #     f"剩余行数: {new_lines}"
            # )
            
        except Exception as e:
            self.progress.stop()
            raise e
    
    def _process_large_content(self, content):
        """处理超大内容的优化方法"""
        try:
            # 使用生成器分批处理，避免内存问题
            def process_lines_generator(text):
                """生成器函数，逐行处理文本"""
                for line in text.splitlines():
                    if line.strip():  # 只保留非空行
                        yield line
            
            # 统计原始行数
            original_lines = content.count('\n') + (1 if content and not content.endswith('\n') else 0)
            
            # 使用生成器处理并收集结果
            filtered_lines = list(process_lines_generator(content))
            new_lines = len(filtered_lines)
            removed_lines = original_lines - new_lines
            
            # 分批更新文本区域以避免内存问题
            self.text_area.delete(1.0, tk.END)
            
            # 分批插入文本（每批1000行）
            batch_size = 1000
            for i in range(0, len(filtered_lines), batch_size):
                batch = filtered_lines[i:i + batch_size]
                batch_text = '\n'.join(batch)
                if i > 0:
                    batch_text = '\n' + batch_text
                self.text_area.insert(tk.END, batch_text)
                
                # 更新进度
                progress = min(100, (i + batch_size) * 100 // len(filtered_lines))
                self.status_label.config(text=f"正在处理空白行... {progress}%")
                self.root.update()
            
            # 更新总行数
            self.total_lines = new_lines
            
            # 停止进度条
            self.progress.stop()
            
            # 更新状态栏
            self.status_label.config(text=f"清除空白行完成 - 删除了 {removed_lines} 行，剩余 {new_lines} 行代码")
            
            # 显示处理结果
            # messagebox.showinfo(
            #     "处理完成", 
            #     f"清除空白行操作完成！\n\n"
            #     f"原始行数: {original_lines}\n"
            #     f"删除空白行: {removed_lines}\n"
            #     f"剩余行数: {new_lines}\n\n"
            #     f"注意：内容较大，已使用优化处理方式"
            # )
            
        except Exception as e:
            self.progress.stop()
            raise e
    
    def set_window_icon(self):
        """设置窗口图标"""
        try:
            # 尝试加载ICO图标文件
            icon_path = "code_organizer.ico"
            if os.path.exists(icon_path):
                self.root.iconbitmap(icon_path)
                print(f"成功加载图标: {icon_path}")
            else:
                # 如果ICO文件不存在，使用内置图标或创建简单图标
                self.create_default_icon()
        except Exception as e:
            print(f"加载图标时出错: {e}")
            self.create_default_icon()
    
    def create_default_icon(self):
        """创建默认图标（如果ICO文件不存在）"""
        try:
            # 创建一个简单的默认图标
            import tempfile
            icon_data = """
            # 创建一个简单的16x16图标
            R0lGODlhEAAQAIAAAAAAAP///yH5BAEAAAEALAAAAAAQABAAAAIgjI+py+0Po5y02ouz3rz7D4bi
            SJbmiabqyrbuC8fyTNf2jef6zvf+DwwKh8Si8YhMKpfMpvMJjUqn1Kr1is1qt9yu9wsOi8fksvmM
            TqvX7Lb7DY/L5/S6/Y7P6/f8vv8PGCg4SFhoeIiYqLjI2Oj4CBkpOUlZaXmJmam5ydnp+QkaKjpK
            Wmp6ipqqusra6voKGys7S1tre4ubq7vL2+v7CxwsPExcbHyMnKy8zNzs/AQdPU1dbX2Nna29zd3t
            /g4eLj5OXm5+jp6uvs7e7v4PHy8/T19vf4+fr7/P3+/w==
            """
            # 这里简化处理，实际应用中应该创建真正的图标
            print("使用默认图标")
        except Exception as e:
            print(f"创建默认图标时出错: {e}")
    
    def run(self):
        """运行应用程序"""
        self.root.mainloop()


def main():
    """主函数"""
    app = CodeOrganizer()
    app.run()


if __name__ == "__main__":
    main()